import numpy as np
import random
import math
import os
import pandas as pd
import hashlib
import random
from typing import Union
from tqdm import tqdm
import multiprocessing 
from util import *




def get_each_ms_kind_reserved_number_one_process(aim_df, ms_kind, data_density, para):
    
    min_window_time=100000
    max_window_time=3500000
    
    if len(aim_df)==0:
        return ms_kind, 0
    min_timestamp = aim_df["timestamp"].min()
    max_timestamp = aim_df["timestamp"].max()
    # print(f"区间：{max_timestamp-min_timestamp}")
    value_list=[]
    
    for idx, row in aim_df.iterrows():
        # 在这里可以对每一行row进行操作
        # if row["rt"]>0:
        rt=max(row["rt"],1)
        value_list.append([row["timestamp"]-min_timestamp, 1])
        value_list.append([row["timestamp"]-min_timestamp+rt, -1])
        
    value_list.sort(key=lambda x: x[0])
    #将value list转化为plot，包含x,y
    plot_x_list = []
    plot_y_list = []
    time=0
    number=0

    for value in value_list:
        if time<=min_window_time and value[0]>=min_window_time:
            plot_x_list.append(min_window_time)
            plot_y_list.append(number)
        if time<=max_window_time and value[0]>=max_window_time:
            plot_x_list.append(max_window_time)
            plot_y_list.append(number)
        time=value[0]
        number+=value[1]
        if time>min_window_time and time<max_window_time:
            plot_x_list.append(time)
            plot_y_list.append(number)
    
     
    if len(plot_y_list)==0 or max(plot_y_list)==0:
        return ms_kind, 0
    max_number=max(plot_y_list) 
    ms_number=1
    # if max_number<=0:
    #     print(f"problem data:\t\t{aim_df.head(10)}\nplot_y_list:{plot_y_list}\nvalue_list:{value_list}")
    # assert max_number>0 
    cold_start_time=stable_random_by_key(ms_kind, 83,1100)
    
    while True:
        #获取指定ms 数量时对应的index
        aim_indices = [i for i, v in enumerate(plot_y_list) if v == ms_number]
        count=0
        acc_value=0
        for index, value in enumerate(aim_indices):
            if index!=len(aim_indices)-1 and plot_y_list[value+1]<ms_number :
                assert plot_y_list[aim_indices[index+1]-1]<ms_number
                count+=1
                acc_value+=(plot_x_list[aim_indices[index+1]]-plot_x_list[aim_indices[index]])
        #单独判断初始和结束是否为空闲
        if plot_y_list[0]<ms_number:
            count+=1
            acc_value+=(plot_x_list[aim_indices[0]]-plot_x_list[0])
        if plot_y_list[-1]<ms_number:
            count+=1
            acc_value+=(plot_x_list[-1]-plot_x_list[aim_indices[-1]])
        
        if count==0:
            #由于约束了ms_number小于最大值，如果这里为0，则一定是微服务数量保持都在其上
            spec_value=0
        else:
            spec_value=acc_value/count*data_density
        
        #判断返回
        if spec_value<=cold_start_time*para:
            if ms_number+1<=max_number:
                ms_number+=1
            else:
                return ms_kind,ms_number
        else:
            return ms_kind, ms_number-1

def get_each_ms_kind_reserved_number(file_name_path, data_density, para_t=0.3):
    df=pd.read_csv(file_name_path)   # traceid  timestamp   service     rpc_id      rpctype   um     dm     rt
    ms_kind_list=df["dm"].unique()
    print(f"ms_kind_list:{len(ms_kind_list)}")
    ms_kind_to_number={}
    
    para_list=[]
    pbar=tqdm(total=len(ms_kind_list))
    
    
            
    with multiprocessing.Pool(processes=32) as pool:
        tasks=[]
        for ms_kind in ms_kind_list:
            print(f"start {ms_kind}")
            mask=(df["dm"].values==ms_kind)
            df_temp=df[mask].sort_values(by="timestamp", ascending=True)
            df=df[~mask]
            para=(df_temp, ms_kind, data_density, para_t)
            hand=pool.apply_async(get_each_ms_kind_reserved_number_one_process, para)
            tasks.append(hand)
        # 提交多个任务
        # tasks = [pool.apply_async(get_each_ms_kind_reserved_number_one_process, para) for para in para_list]    

        for future in tasks:
            ms_kind, number=future.get()   
            pbar.update(1)
            ms_kind_to_number[ms_kind]=number
            print(f"{ms_kind}:{number}")
    
    return ms_kind_to_number
    
    

def Prepare_for_normal():
    ms_kind_to_number_all={}
    for trace_id in range(10):
        aim_file_name_path=get_datas_dir()+f"/CallGraph_dataset_0d11_0d12_new_cleaned_0.1_s{trace_id}_history.csv"
        print(f"aim_file_name_path:{aim_file_name_path}")
        ms_kind_to_number=get_each_ms_kind_reserved_number(aim_file_name_path, 1/10)
        for key in ms_kind_to_number.keys():
            if key in ms_kind_to_number_all.keys():
                ms_kind_to_number_all[key].append(ms_kind_to_number[key])
            else:
                ms_kind_to_number_all[key]=[ms_kind_to_number[key]]
    
    # 将每个列表转为 Series，作为行；自动补齐缺失
    df = pd.DataFrame.from_dict({k: pd.Series(v) for k, v in ms_kind_to_number_all.items()}, orient="index")

    # 美化列名，并把键作为普通列导出
    df.columns = [f"v{i}" for i in range(df.shape[1])]
    df.fillna(0, inplace=True)
    df_sorted = df.loc[
        df.select_dtypes(include="number")
        .mean(axis=1)                    # 行均值（忽略 NaN）
        .sort_values(ascending=False)
        .index]
    df_sorted = df_sorted.rename_axis("key").reset_index()
    df_sorted.to_csv(get_dealed_data_dir()+"/heuristic_plan.csv", index=False)


def Prepare_for_dynamic():
    
    
    for dynamic in [0.0]:
        ms_kind_to_number_all={}
        
        aim_file_name_path=get_datas_dir()+f"/CallGraph_dataset_0d11_0d12_dynamic{round(dynamic,1)}_{round(dynamic+0.2,1)}_history.csv"
        print(f"aim_file_name_path:{aim_file_name_path}")
        ms_kind_to_number=get_each_ms_kind_reserved_number(aim_file_name_path,1)
        for key in ms_kind_to_number.keys():
            if key in ms_kind_to_number_all.keys():
                ms_kind_to_number_all[key].append(ms_kind_to_number[key])
            else:
                ms_kind_to_number_all[key]=[ms_kind_to_number[key]]
    
        # 将每个列表转为 Series，作为行；自动补齐缺失
        df = pd.DataFrame.from_dict({k: pd.Series(v) for k, v in ms_kind_to_number_all.items()}, orient="index")

        # 美化列名，并把键作为普通列导出
        df.columns = [f"v{i}" for i in range(df.shape[1])]
        df.fillna(0, inplace=True)
        df_sorted = df.loc[
            df.select_dtypes(include="number")
            .mean(axis=1)                    # 行均值（忽略 NaN）
            .sort_values(ascending=False)
            .index]
        df_sorted = df_sorted.rename_axis("key").reset_index()
        df_sorted.to_csv(get_dealed_data_dir()+f"/heuristic_plan_dynamic{round(dynamic,1)}_{round(dynamic+0.2,1)}_.csv", index=False)
    
    
def Prepare_for_size():
    
    for size in [0]:
        ms_kind_to_number_all={}
        
        aim_file_name_path=get_datas_dir()+f"/CallGraph_dataset_0d11_0d12_size{round(size)}_{round(size+10)}_history.csv"
        print(f"aim_file_name_path:{aim_file_name_path}")
        ms_kind_to_number=get_each_ms_kind_reserved_number(aim_file_name_path,1)
        for key in ms_kind_to_number.keys():
            if key in ms_kind_to_number_all.keys():
                ms_kind_to_number_all[key].append(ms_kind_to_number[key])
            else:
                ms_kind_to_number_all[key]=[ms_kind_to_number[key]]
    
        # 将每个列表转为 Series，作为行；自动补齐缺失
        df = pd.DataFrame.from_dict({k: pd.Series(v) for k, v in ms_kind_to_number_all.items()}, orient="index")

        # 美化列名，并把键作为普通列导出
        df.columns = [f"v{i}" for i in range(df.shape[1])]
        df.fillna(0, inplace=True)
        df_sorted = df.loc[
            df.select_dtypes(include="number")
            .mean(axis=1)                    # 行均值（忽略 NaN）
            .sort_values(ascending=False)
            .index]
        df_sorted = df_sorted.rename_axis("key").reset_index()
        df_sorted.to_csv(get_dealed_data_dir()+f"/heuristic_plan_size{round(size)}_{round(size+10)}_.csv", index=False)
# print("large")
Prepare_for_size()
# Prepare_for_dynamic()









